<?php
/**
 * 
 * vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
 * 
 * A highly simplified table-processing class that hints the view on how to 
 * present the table.
 *
 * This class has been heavily adapted from Solar_Form which was used as the 
 * basis for creating this class.
 *
 * @category Xdms
 * 
 * @package Xdms_Table HTML Table processor with automated loading and presentation
 * hinting.
 * 
 * @author Paul M. Jones <pmjones@solarphp.com>
 *
 * @author Matthew Weier O'Phinney <mweierophinney@gmail.com>
 *
 * @author Abu Bakar Al-Idrus <alidrus@gmail.com>
 * 
 * @license http://opensource.org/licenses/bsd-license.php BSD
 * 
 * @see Class::Xdms_View_Helper_Table
 *
 * @version $Id$
 * 
 */
class Xdms_Table extends Solar_Base
{
    /**
     * 
     * Default configuration values for elements in table.
     * 
     * @var array
     * 
     */
    protected $_Xdms_Table = array(
    );

    /**
     * 
     * Table _table array.
     * 
     * The `$_table` array contains all components in the table including 
     * attributes.
     * 
     * @var array
     * 
     */
    protected $_table = array(
        'attribs'  => array(),
        'caption'  => array(),
        'colgroup' => array(),
        'col'      => array(),
        'head'     => array(),
        'foot'     => array(),
        'body'     => array(),
        'row'      => array(),
    );

    /**
     *
     * Resets the table to its originally-configured state.
     *
     * This clears out all components of the table including attributes.
     *
     * @return void
     *
     */
    public function reset() {
        $this->_table = array(
            'attribs'  => array(),
            'caption'  => array(),
            'colgroup' => array(),
            'col'      => array(),
            'head'     => array(),
            'foot'     => array(),
            'body'     => array(),
            'row'      => array(),
        );
    }

    /**
     *
     * Sets attributes for the table tag itself
     *
     * @param string|array $attribs Attributes for the table
     *
     * @return void
     *
     */
    public function setAttribs($attribs = null) {
        if (is_array($attribs) || is_string($attribs)) {
            $this->_table['attribs'] = $attribs;
        }
    }

    /**
     *
     * Sets attributes for a column via the <col> tag
     *
     * @param array $attribs Attributes for the column.
     *
     * @return void
     * 
     */
    public function setCol($attribs = array()) {
        $this->_table['col'][] = array('attribs' => $attribs);
    }

    /**
     *
     * Sets attributes for a number of columns via the <colgroup> tag
     *
     * @param array $attribs Attributes for the column group.
     *
     * @return void
     * 
     */
    public function setColGroup($attribs = array()) {
        // set new <colgroup> with attributes
        $this->_table['colgroup'][] = array('attribs' => $attribs);
    }

    /**
     *
     * Sets table caption content and attributes.
     *
     * @param string $caption Caption for the table
     *
     * @return void
     *
     */
    public function setCaption($caption = null, $attribs = array()) {
        // set table caption content (forcibly cast to string)
        $this->_table['caption']['content'] = (string) $caption;

        // set table caption attributes
        $this->_table['caption']['attribs'] = $attribs;
    }

    /**
     *
     * Sets a row in table head.
     *
     * Attributes may be overridden individually for a cell.
     *
     * @param array $cols Array of columns in the table head
     *
     * @return void
     *
     */
    public function setHeadRow($cols = null, $attribs = array(), $use_th = true, $row_id = null) {
        $this->_setRow('head', $cols, $attribs, $use_th, $row_id);
    }

    /**
     *
     * Sets one column in the table head.
     *
     * @param int $row_id Array index of the row for which to set the column.
     *
     * @param string|array $col Column specification. If string, then use that
     * as the content. If array, then extract 'content' as content and 'attribs'
     * as the attribute list.
     *
     * @param array $attribs Set these attribs on the cell; the key is the
     * attribute name, and the value is the attribute value.
     *
     * @param bool $use_th Use <th> for column if true, else use <td>
     *
     * @return void
     *
     */
    public function setHeadColumn($row_id, $col = null, $attribs = array(), $use_th = true) {
        $this->_setColumn('head', $row_id, $col, $attribs, $use_th);
    }

    /**
     *
     * Sets one row in table foot.
     *
     * Attributes may be overridden individually for a cell.
     *
     * @param array $cols Array of columns in the table head
     *
     * @return void
     *
     */
    public function setFootRow($cols = null, $attribs = array(), $use_th = true, $row_id = null) {
        $this->_setRow('foot', $cols, $attribs, $use_th, $row_id);
    }

    /**
     *
     * Sets one column in the table foot.
     *
     * @param int $row_id Array index of the row for which to set the column.
     *
     * @param string|array $col Column specification. If string, then use that
     * as the content. If array, then extract 'content' as content and 'attribs'
     * as the attribute list.
     *
     * @param array $attribs Set these attribs on the cell; the key is the
     * attribute name, and the value is the attribute value.
     *
     * @param bool $use_th Use <th> for column if true, else use <td>
     *
     * @return void
     *
     */
    public function setFootColumn($row_id, $col = null, $attribs = array(), $use_th = true) {
        $this->_setColumn('foot', $row_id, $col, $attribs, $use_th);
    }

    /**
     *
     * Sets one row in table body.
     *
     * Attributes may be overridden individually for a cell.
     *
     * @param array $cols Array of columns in the table head
     *
     * @return void
     *
     */
    public function setBodyRow($cols = null, $attribs = array(), $use_th = false, $row_id = null) {
        $this->_setRow('body', $cols, $attribs, $use_th, $row_id);
    }

    /**
     *
     * Sets one column in the table body.
     *
     * @param int $row_id Array index of the row for which to set the column.
     *
     * @param string|array $col Column specification. If string, then use that
     * as the content. If array, then extract 'content' as content and 'attribs'
     * as the attribute list.
     *
     * @param array $attribs Set these attribs on the cell; the key is the
     * attribute name, and the value is the attribute value.
     *
     * @param bool $use_th Use <th> for column if true, else use <td>
     *
     * @return void
     *
     */
    public function setBodyColumn($row_id, $col = null, $attribs = array(), $use_th = true) {
        $this->_setColumn('body', $row_id, $col, $attribs, $use_th);
    }

    /**
     *
     * Get the table structure.
     *
     * @return array
     *
     */
    public function getTable() {
        return $this->_table;
    }

    /**
     *
     * Sets a row
     *
     * Attributes may be overridden individually for a cell.
     *
     * @param array $cols Array of columns in the table head
     *
     * @return void
     *
     */
    private function _setRow($type, $cols = null, $attribs = array(), $use_th = true, $row_id = null) {
        // was $row_id set?
        if (! $row_id) {
            // set default row id to -1
            $row_id = -1;

            // reset rows, will return false if section is empty
            if (reset($this->_table[$type])) {
                $row_id = key($this->_table[$type]);
                // advance row id to the last row of the section
                while (next($this->_table[$type])) {
                    $row_id = key($this->_table[$type]);
                }
            }

            $row_id++;
        }

        // add cols to new row in head section
        foreach((array) $cols as $col) {
            $this->_setColumn($type, $row_id, $col, $attribs, $use_th);
        }
    }

    /**
     *
     * Sets one column in the row
     *
     * @param string $type Type of row to set (head, foot, body or just row)
     *
     * @param int $row_id Array index of the row for which to set the column.
     *
     * @param string|array $col Column specification. If string, then use that
     * as the content. If array, then extract 'content' as content and 'attribs'
     * as the attribute list.
     *
     * @param array $attribs Set these attribs on the cell; the key is the
     * attribute name, and the value is the attribute value.
     *
     * @param bool $use_th Use <th> for column if true, else use <td>
     *
     * @return void
     *
     */
    private function _setColumn($type, $row_id, $col = null, $attribs = array(), $use_th = true) {
        // throw exception if col is neither array nor string
        if (!is_array($col) && !is_string($col)) {
            throw $this->_exception('ERR_UNKNOWN_COLUMN_TYPE', array(
                'col' => $col
            ));
        }

        // temporary array to store column info
        $temp_col = array();

        // set content (if $col is string)
        if (is_string($col)) {
            $temp_col['content'] = $col;
        }

        // set content (if $col is array)
        if (is_array($col) && array_key_exists('content', $col)) {
            $temp_col['content'] = $col['content'];
        }

        // set attributes
        $temp_col['attribs'] = (array) $attribs;

        // set overrides for attributes in this column
        if (is_array($col) && array_key_exists('attribs', $col)) {
            $temp_col['attribs'] = (array) $col['attribs'];
        }

        // set use_th for this col
        $temp_col['use_th']  = (bool) $use_th;

        // set override for use_th in this col
        if (is_array($col) && array_key_exists('use_th', $col)) {
            $temp_col['use_th']  = (bool) $col['use_th'];
        }

        // add column to the current head data
        $this->_table[$type][$row_id][] = $temp_col;
    }
}
